﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using QuantitativeInvestment.Bean;
using QuantitativeInvestment.Model;
using QuantitativeInvestment.Tools;
using QuantitativeInvestment.StockPool;
namespace QuantitativeInvestment.Container
{
    //固定一个周期操作一次,并且只含有一个Model
    class SimpleContainer:Container
    {
        //已经买入并卖出的投资组合
        public PortfolioManager portfolioMananger;

       
        
        public SimpleContainer()
        {
            this.portfolioMananger = new PortfolioManager();
            this.portfolioMananger.holdPortfolioList = new List<Portfolio>();
            this.portfolioMananger.soldPortfolioList = new List<Portfolio>();
            this.portfolioMananger.stockPoolPortfolioList = new List<Portfolio>();
            Parameter p = new Parameter("操作周期", 30);
            this.paraList.Add(p.name, p);

             p = new Parameter("详细输出", "否");
             p.type = "enum";
             p.enumList.Add("是");
             p.enumList.Add("否");
            this.paraList.Add(p.name, p);

            StockPool.StockPool pool = new IndexStockPool();
            this.poolList.Add(pool);
            this.name = "简单容器";

            //投资组合特征分析器
            this.analyserList = new List<CharacterAnalyzer.CharacterAnalyzer>();
       //     CharacterAnalyzer.MarketValueAnalyzer an=new CharacterAnalyzer.MarketValueAnalyzer();
    //        an.container=this;
     //       this.analyserList.Add(an);
        }

        
        public override  void run()
        {
            this.portfolioMananger.soldPortfolioList.Clear();

            string startDate = this.paraList["开始时间"].value.ToString();
            string endDate = this.paraList["结束时间"].value.ToString();

            this.tradingDates = this.dataModel.getTradingDateList(startDate, endDate);

            if(!this.isTestModel)
                this.progressValue = 0.0;
          
            int startPosition = this.tradingDates.IndexOf(this.paraList["开始时间"].value.ToString());
            int endPosition = this.tradingDates.IndexOf(this.paraList["结束时间"].value.ToString());
            int actionPeriod=Int32.Parse(this.paraList["操作周期"].value.ToString());
            string currentDate;
            StockPool.StockPool pool = this.poolList[0];

            double  step = 80.0 / ((endPosition - startPosition) / actionPeriod);


            int maxHoldingTime = Int32.Parse(this.modelList[this.modelList.Count - 1].paraList["持有时间"].value.ToString());
            portfolioMananger.maxHoldPeriod = maxHoldingTime;
            //进行计算
            for (int position = startPosition; position <= endPosition; position = position + actionPeriod)
            {
                currentDate = this.tradingDates[position];
                List<TradingStock> tradingStocks = pool.getStocks(this.tradingDates[position]);
                //更新最新输入的股票到内存股票数据库
                this.updateStocks(tradingStocks);

                //设置一期的买入
                List<TradingStock> selectedStocks = tradingStocks;
                for (int i = 0; i < this.modelList.Count; i++)
                {
                    selectedStocks = this.modelList[i].buy(selectedStocks, this.tradingDates[position]);
                }

                //根据最后一个模型的卖出逻辑，卖出
                List<TradingStock> soldStocks = this.modelList[this.modelList.Count - 1].sell(selectedStocks, this.tradingDates[position]);

                if ( position + maxHoldingTime <= endPosition )
                {
                    //如果是第一组没有被选到的股票组合就不加入
                    if (!(soldStocks.Count == 0 && this.portfolioMananger.soldPortfolioList.Count == 0))
                    {
                        //买入并且又卖出的股票组合
                        Portfolio soldPortfolio = new Portfolio();
                        soldPortfolio.startDate = this.tradingDates[position];
                        soldPortfolio.endDate = this.tradingDates[position + maxHoldingTime];
                        soldPortfolio.stockList = soldStocks;

                        this.portfolioMananger.soldPortfolioList.Add(soldPortfolio);

                        //备选股票池的投资组合
                        Portfolio stockPoolPortfolio = new Portfolio();
                        stockPoolPortfolio.startDate = soldPortfolio.startDate;
                        stockPoolPortfolio.endDate = soldPortfolio.endDate;
                        stockPoolPortfolio.stockList = tradingStocks;
                        this.portfolioMananger.stockPoolPortfolioList.Add(stockPoolPortfolio);
                    }
                }
                else if (position + maxHoldingTime > endPosition)
                {
                    Portfolio holdPortfolio = new Portfolio();
                    holdPortfolio.startDate = this.tradingDates[position];

                    holdPortfolio.stockList = selectedStocks;
                    this.portfolioMananger.holdPortfolioList.Add(holdPortfolio);

                    //备选股票池的投资组合
                    Portfolio stockPoolPortfolio = new Portfolio();
                    stockPoolPortfolio.startDate = holdPortfolio.startDate;
                    stockPoolPortfolio.stockList = tradingStocks;
                    this.portfolioMananger.stockPoolPortfolioList.Add(stockPoolPortfolio);
                }


                //进度条前进

                if (!this.isTestModel)
                    progressValue = progressValue + step; ;
               
            }




           //计算每一期基本数据
           this.caculateStatistics();

           //投资组合分析
           this.portfolioMananger.caculateStatics();

           if (!isTestModel)
           {
               XmlDataSource dataSource = new XmlDataSource();
               dataSource.createTestModeDocument();
               string fileName = "普通模式-" + this.name;
               foreach (Model.Model model in this.modelList)
               {
                   fileName = fileName + "-" + model.name;
               }

               bool isDatailed = false;
               if (this.paraList["详细输出"].value.ToString() == "是")
                   isDatailed = true;

               dataSource.addPortfolios(this, isDatailed);
               dataSource.saveDoc(System.Windows.Forms.Application.StartupPath + "/Results/" + fileName + ".xml");

               this.progressValue = 100;
           }
        }

        /// <summary>
        /// 在测试模式之下,参数组合
        /// </summary>
        public override void testModeRun()
        {
            this.progressValue = 0;
            int period = 30;
            XmlDataSource xmlDataSource = new XmlDataSource();
            xmlDataSource.createTestModeDocument();



            this.isTestModel = true;
            bool isDatailed = false;
            if (this.paraList["详细输出"].value.ToString() == "是")
                isDatailed = true;


            double currentTimes = 0;
            int totalNum = 60;
            int step = 5;
            int totalTimes = (totalNum / step);
            for (period = 5; period < totalNum; period = period + step)
            {
                this.modelList[0].paraList["观察时间"].value = period;



                this.run();
                currentTimes++;
                xmlDataSource.addPortfolios(this, isDatailed);

                this.progressValue = currentTimes / totalTimes * 100;  
               
            }
            string fileName = "测试模式—"+this.name;
            foreach (Model.Model model in this.modelList)
            {
                fileName = fileName + "-" + model.name;
            }
            
            xmlDataSource.saveDoc( System.Windows.Forms.Application.StartupPath + "/Results/" + fileName + ".xml");

            this.progressValue = 100;
        }

        public override void lastestPortfolios()
        {
          
            string startDate = this.paraList["开始时间"].value.ToString();
            string endDate = this.paraList["结束时间"].value.ToString();

            this.tradingDates = this.dataModel.getTradingDateList(startDate, endDate);


            int startPosition = this.tradingDates.IndexOf(this.paraList["开始时间"].value.ToString());
            int endPosition = this.tradingDates.IndexOf(this.paraList["结束时间"].value.ToString());

            string currentDate;
            StockPool.StockPool pool = this.poolList[0];

            int position = endPosition;
            currentDate = this.tradingDates[position];
            List<TradingStock> tradingStocks = pool.getStocks(this.tradingDates[position]);

            this.progressValue = 10;
            //更新最新输入的股票到内存股票数据库
            this.updateStocks(tradingStocks);

            //设置一期的买入
            List<TradingStock> selectedStocks = tradingStocks;
            for (int i = 0; i < this.modelList.Count; i++)
            {
                selectedStocks = this.modelList[i].buy(selectedStocks, this.tradingDates[position]);
            }
            Portfolio p=new Portfolio();
            p.startDate = endDate;
            p.stockList = selectedStocks;


            XmlDataSource dataSource = new XmlDataSource();
            string fileName = "最新组合-"+this.name;
            foreach (Model.Model model in this.modelList)
            {
                fileName = fileName + "-" + model.name;
            }
            this.portfolioMananger.holdPortfolioList.Clear();
            this.portfolioMananger.holdPortfolioList.Add(p);

            dataSource.outputPortfolios(this.portfolioMananger.holdPortfolioList, System.Windows.Forms.Application.StartupPath + "/Results/" + fileName + ".xml");
            this.progressValue = 100;
        }
      
        //收益统计
        public override void caculateStatistics()
        {
            string benchMarkIndexName=this.paraList["基准指数"].value.ToString();
            double cost = Double.Parse(this.paraList["交易成本"].value.ToString());
            foreach (Portfolio p in this.portfolioMananger.soldPortfolioList)
            {
                double stockMinIncrease = 999;
                double stockMaxIncrease = -999;
                double totalIncrease = 0;
                int successNum = 0;

                p.benchMarkIncrease = this.dataModel.getIndexIncreaseByName(p.startDate, p.endDate, benchMarkIndexName);

                for (int i = 0; i < p.stockList.Count; i++)
                {
                    TradingStock tradingStock=p.stockList[i];
                    this.setBuyPrice(tradingStock);
                    this.setSellPrice(tradingStock);
                    double stockIncrease = tradingStock.getIncrease() - cost;

                    if (stockIncrease >= p.benchMarkIncrease)
                        successNum++;

                    if (stockMinIncrease > stockIncrease)
                        stockMinIncrease = stockIncrease;
                    if (stockMaxIncrease < stockIncrease)
                        stockMaxIncrease = stockIncrease;
                    totalIncrease = totalIncrease + stockIncrease; 
                }
                p.minIncrease = stockMinIncrease;
                p.maxIncrease = stockMaxIncrease;
             
                if (p.stockList.Count > 0)
                {
                    p.averageIncrease = totalIncrease / p.stockList.Count;
                    p.successRate = 1.0 * successNum / p.stockList.Count;
                }
                p.averageYearIncrease = Math.Pow((1 + p.averageIncrease), 250 / portfolioMananger.maxHoldPeriod) - 1;

                   
                p.excessIncrease = p.averageIncrease - p.benchMarkIncrease;

            }
            
            //进行统计分析
            foreach(CharacterAnalyzer.CharacterAnalyzer analyzer in this.analyserList)
            {
                foreach (Factor.Factor factor in analyzer.factorList)
                {
                    foreach (Stock stock in this.stocks.Values)
                    {
                        factor.addFactorValue(stock);
                    }
                }
                analyzer.analyse(this.portfolioMananger);
            }



        }
    }
}
